package playbook

import (
	"sync"
	"time"
)

type CallbackHandler func(data map[string]interface{})

type responseManager struct {
	timeout time.Duration
	rmu     sync.RWMutex
	rid     int
	rr      map[int]*response
}

func newResponseManager() *responseManager {
	return &responseManager{
		rid:     0,
		rmu:     sync.RWMutex{},
		rr:      make(map[int]*response, 30),
		timeout: time.Duration(1 * time.Second),
	}
}

func (rm *responseManager) clean() {
	rm.rid = 0
}
func (rm *responseManager) SetTimeout(ms time.Duration) {
	rm.timeout = time.Duration(time.Millisecond * ms)
}
func (rm *responseManager) onResponse(rid int, openId string, value interface{}) {
	//fmt.Println("accept room rid:", msg.Rid)
	rm.rmu.RLock()
	response, ok := rm.rr[rid]
	rm.rmu.RUnlock()
	if !ok {
		return
	}
	response.Response(openId, value)
}
func (rm *responseManager) addResponse(count int, response *response) int {
	rm.rmu.Lock()
	rm.rid++
	rid := rm.rid
	rm.rr[rid] = response
	rm.rmu.Unlock()

	//fmt.Println("send room rid:", rid)
	response.num = count
	response.time = time.AfterFunc(rm.timeout, func() {
		rm.rmu.RLock()
		response := rm.rr[rid]
		rm.rmu.RUnlock()
		if response != nil {
			if response.callback != nil {
				response.Callback(false)
			}
			response.finish()
		}
	})
	response.finish = func() {
		rm.rmu.Lock()
		delete(rm.rr, rid)
		rm.rmu.Unlock()
		response.Release()
	}
	//fmt.Println(response)
	return rid
}

type response struct {
	num      int
	resNum   int
	callback CallbackHandler
	result   map[string]interface{}
	time     *time.Timer
	finish   func()
	mu       sync.Mutex
}

var (
	responsePool = sync.Pool{}
)

func init() {
	responsePool.New = func() interface{} {
		r := &response{}
		r.init()
		return r
	}
}

func newResponse(callback CallbackHandler) *response {
	if callback == nil {
		return nil
	}
	res := responsePool.Get().(*response)
	res.callback = callback
	res.num = 0
	res.resNum = 0
	return res
}

func (res *response) init() {
	res.result = make(map[string]interface{})
}

func (res *response) Release() {
	res.callback = nil
	res.init()
	responsePool.Put(res)
}

func (res *response) Response(from string, data interface{}) {
	res.mu.Lock()
	res.resNum++
	res.result[from] = data
	res.mu.Unlock()
	if res.resNum == res.num {
		res.Callback(true)
		res.finish()
	}
}

func (res *response) Callback(success bool) {
	if res.callback != nil {
		res.callback(res.result)
	}
	if res.time != nil {
		res.time.Stop()
	}
}
